package picol.controller;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import picol.model.Model;
import picol.model.exception.FileNameException;
import picol.model.jjgener.ParseException;
import picol.view.View;
import picol.view.exception.SaveException;
import picol.view.utility.PCommand;

/**
 * Classe du controller
 * @author Aurélien Marcel - Julien Sanderson
 */
public class ControlerImp implements Controler, CaretListener, MouseListener {

	private View view;
	private Model model;

	/**
	 * Default Constructor
	 */
	public ControlerImp(View _view, Model _model) {
		this.view = _view;
		this.model = _model;
	}

	/**
	 * Gestion des actions et des evenements
	 * @param ae
	 */
	public void actionPerformed(ActionEvent ae) {
		//récupération de la clé
		int ident = PCommand.getKey(ae.getActionCommand());
		switch (ident) {
			case PCommand.IDENT_RUN:
				this.run();
				break;
			case PCommand.IDENT_SAVE:
				this.save();
				break;
			case PCommand.IDENT_OPEN:
				this.open();
				break;
			case PCommand.IDENT_DEBUG:
				try {
					if (this.view.saveFile()) {
						this.debug();
					}
				} catch (SaveException ex) {
					this.view.appendOutput("Failed to save");
				}

				break;
			case PCommand.IDENT_STOP:
				this.stop();
				break;
			case PCommand.IDENT_NEXT:
				this.next();
				break;
			case PCommand.IDENT_NEW:
				this.view.newFile();
				break;
			case PCommand.IDENT_SAVEAS:
				this.saveAs();
				break;
			default:
				break;
		}
	}

	/**
	 * Modification du champ de texte
	 * @param ce
	 */
	public void caretUpdate(CaretEvent ce) {

		// Si une nouvelle ligne est cree
		if (this.view.getLineCount() != this.view.getCounterList()) {
			this.view.setCounterList(this.view.getLineCount());
			this.view.setLineCount();
		}

	}

	/**
	 * Lancement du programme
	 */
	private void run() {
		try {
			if (this.view.saveFile()) {
				this.view.setOutput("Running...");
				this.model.parse(this.view.getProjectPath());
				this.model.setDebugMode(false);
				this.view.setDebugMode(false);
				this.model.launch();
				this.view.refreshMemory(this.model.getVarList());
			}
		} catch (FileNameException ex) {
			this.view.appendOutput("Incorrect File...");
		} catch (ParseException ex) {
			this.view.appendOutput("Problem with code! Unknown symbol >> " + ex.currentToken.image + " << Line:" + ex.currentToken.beginLine + ", column:" + ex.currentToken.beginColumn);
			this.view.appendOutput(ex.toString());
		} catch (SaveException ex) {
			this.view.appendOutput("Failed to save");
		} catch (RuntimeException ex) {
			this.view.appendOutput(ex.toString());
		}
	}

	/**
	 * Lancement du programme en mode debug
	 */
	private void debug() {
		try {
			this.model.parse(this.view.getProjectPath());
		} catch (FileNameException ex) {
			this.view.appendOutput("Incorrect File...");
		} catch (ParseException ex) {
			this.view.appendOutput("Problem with code! Unknown symbol >> " + ex.currentToken.image + " << Line:" + ex.currentToken.beginLine + ", column:" + ex.currentToken.beginColumn);
		}
		this.model.setDebugMode(true);
		boolean test = !this.model.launch();
		this.view.setDebugMode(test);
		this.model.setDebugMode(test);
		this.view.refreshMemory(this.model.getVarList());
	}

	/**
	 * Gestion des evenements au clic
	 * @param me
	 */
	public void mouseClicked(MouseEvent me) {

		//on effectue une action seulement si on réalise un double clique
		if (me.getClickCount() == 2) {
			int line = this.view.getClickedLine();
			this.view.setClickedLine(line);
			this.model.setDebugLine(line);
		}
	}

	public void mousePressed(MouseEvent me) {
	}

	public void mouseReleased(MouseEvent me) {
	}

	public void mouseEntered(MouseEvent me) {
	}

	public void mouseExited(MouseEvent me) {
	}

	/**
	 * Sauvegarde d'un fichier
	 */
	private void save() {
		try {
			this.view.saveFile();
		} catch (SaveException ex) {
			this.view.appendOutput("Failed to save");
		}
	}

	/**
	 * Ouverture d'un fichier
	 */
	private void open() {
		try {
			this.view.openFile();
		} catch (FileNotFoundException ex) {
			this.view.appendOutput("Failed to open file");
		}
	}

	/**
	 * Arret du mode debug
	 */
	private void stop() {
		this.view.setDebugMode(false);
		this.view.appendOutput("DEBUG STOPPED");
	}

	/**
	 * Lancement de l'instruction suivante
	 */
	private void next() {
		int line = this.model.getDebugLine();
		this.model.setDebugLine(++line);
		this.debug();
	}

	/**
	 * Enregistrer sous
	 */
	private void saveAs() {
		try {
			this.view.saveAsFile();
		} catch (SaveException ex) {
			this.view.appendOutput("Failed to save");
		}
	}
}
